package com.nineclock.auth.config;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.nineclock.auth.entity.IntegrationAuthenticationEntity;
import com.nineclock.auth.processor.AuthenticationProcessor;
import com.nineclock.auth.threadlocal.IntegrationAuthenticationHolder;
import com.nineclock.auth.threadlocal.UserHolder;
import com.nineclock.common.entity.UserInfo;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.dto.SysRoleDTO;
import com.nineclock.system.dto.SysUserDTO;
import com.nineclock.system.feign.SysUserFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    List<AuthenticationProcessor> processors;
    @Autowired
    SysUserFeign userFeign;
    /**
     * 1. 根据用户名从数据库获取用户信息
     * 2. 封装UserDetails 并返回
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    //明文密码为 123456
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1. 从当前线程中获取 认证实体对象
        IntegrationAuthenticationEntity entity = IntegrationAuthenticationHolder.get();
        //2. 获取使用哪种处理器
        AuthenticationProcessor processor = this.chooseAuthenticationProcessor(entity);

        //3. 获取 用户信息
        SysUserDTO userDTO = processor.authenticate(entity);
        //用户详情类中将查询结果,封装到UserInfo中
        UserInfo userInfo = BeanHelper.copyProperties(userDTO, UserInfo.class);

        //完善认证操作（判断是否有资格访问 pc端）
        String clientId = entity.getAuthParameter("client_id");
        String companyId = entity.getAuthParameter("company_id");
        //判断是否是 pc端登录, 必须是管理员
        if(clientId != null && clientId.equals("pc_client")){
            //判断是否是管理员
            //根据用户信息，查询 员工 列表 信息（包含角色信息）， 判定是否是管理员
            //第一次 点击登录
            if(StrUtil.isEmpty(companyId)){
                //根据用户id 查询员工列表（包含角色信息）
                List<SysCompanyUserDTO> companyUserDTOList = userFeign.queryCompanyUser(userDTO.getId(), null).getData();
                //检查是否管理员
                Boolean flag = this.checkAdminCompanyUserList(companyUserDTOList);
                if(!flag){
                    throw new NcException(ResponseEnum.USER_NOT_COMPANY_ADMIN);
                }
                //封装 userInfo，  把企业信息封装到 userInfo中
                wrapper(userInfo, companyUserDTOList.get(0));
            }
            //第二次 选择加入企业
            else{
                //根据用户id 和企业 id 查询员工列表（包含角色信息）
                List<SysCompanyUserDTO> companyUserDTOList = userFeign.queryCompanyUser(userDTO.getId(), Long.valueOf(companyId)).getData();
                //检查是否管理员
                Boolean flag = this.checkAdminCompanyUserList(companyUserDTOList);
                if(!flag){
                    throw new NcException(ResponseEnum.USER_NOT_COMPANY_ADMIN);
                }
                //封装 userInfo，  把企业信息封装到 userInfo中
                wrapper(userInfo, companyUserDTOList.get(0));
            }

        }
        //否则就是app端的登录
        else {
            //如果 企业id为null， 则使用最后一次登录使用的企业
            if(StrUtil.isEmpty(companyId)){
                companyId = userDTO.getLastLoginCompanyId() + "";
            }
            //获取员工列表
            List<SysCompanyUserDTO> companyUserDTOS = userFeign.queryCompanyUser(userDTO.getId(), Long.valueOf(companyId)).getData();

            if(CollectionUtil.isNotEmpty(companyUserDTOS)){
                //封装 userInfo，  把企业信息封装到 userInfo中
                wrapper(userInfo, companyUserDTOS.get(0));
            }

        }

        UserHolder.set(userInfo);

        //4. 封装UserDetails对象，并返回
        //创建一个假的权限
        if(userDTO !=null){
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_ADMIN");
            User user = new User(JSONUtil.toJsonStr(userInfo), userDTO.getPassword(), Arrays.asList(authority) );
            return user;
        }else {
            throw new NcException(ResponseEnum.INVALID_USERNAME_PASSWORD);
        }


    }
    private void wrapper(UserInfo userInfo, SysCompanyUserDTO companyUserDTO) {
        userInfo.setCompanyId(companyUserDTO.getCompanyId());
        userInfo.setCompanyName(companyUserDTO.getCompanyName());
        userInfo.setCompanyUserId(companyUserDTO.getId());
        userInfo.setDepartmentId(companyUserDTO.getDepartmentId());
        userInfo.setDepartmentName(companyUserDTO.getDepartmentName());
        userInfo.setPost(companyUserDTO.getPost());
        userInfo.setWorkNumber(companyUserDTO.getWorkNumber());
        userInfo.setTimeEntry(companyUserDTO.getTimeEntry());
        //必须要设置 此字段（如不设置 app端，所有操作 ，显示 "未认证" ）
        userInfo.setEnable(true);

    }
    /**
     * 检测员工是否是管理员
     */
    public Boolean checkAdminCompanyUserList(List<SysCompanyUserDTO> companyUserDTOS){
        if(CollectionUtil.isNotEmpty(companyUserDTOS)){
            for (SysCompanyUserDTO companyUserDTO : companyUserDTOS) {
                //获取角色信息
                List<SysRoleDTO> roles = companyUserDTO.getRoles();
                if(CollectionUtil.isNotEmpty(roles)){
                    for (SysRoleDTO role : roles) {
                        if(role.getRoleName().startsWith("ROLE_ADMIN")){
                            return true;
                        }
                    }
                }
            }

        }
        return false;
    }

    public AuthenticationProcessor chooseAuthenticationProcessor(IntegrationAuthenticationEntity entity){
        if(CollectionUtil.isNotEmpty(processors)){
            for (AuthenticationProcessor processor : processors) {
                //如果支持该处理器， 则返回
                if(processor.support(entity)){
                    return processor;
                }
            }
        }
        return null;
    }
}